#include "stdafx.h"
#include "WndResizer.h"

CWndResizer::CWndResizer(HANDLE hHeap, DWORD dwMaxControls, HWND hParentWnd):
	m_hHeap(hHeap)
{
	RECT rect;
	
	GetClientRect(hParentWnd, &rect);
	Init(dwMaxControls, rect.right - rect.left, rect.bottom - rect.top);
}

CWndResizer::CWndResizer(HANDLE hHeap, DWORD dwMaxControls, DWORD dwInitialW, DWORD dwInitialH):
	m_hHeap(hHeap)
{
	Init(dwMaxControls, dwInitialW, dwInitialH);
}

CWndResizer::~CWndResizer()
{
	HeapFree(m_hHeap, 0, m_pItems);
}

void CWndResizer::Init(DWORD dwMaxControls, DWORD dwInitialW, DWORD dwInitialH)
{
	m_dwMaxControls = dwMaxControls;
	
	m_dwOrgW = dwInitialW;
	m_dwOrgH = dwInitialH;
	m_dwAdded = 0;
	
	m_pItems = (RITEM*)HeapAlloc(m_hHeap, 0, dwMaxControls * sizeof(RITEM));
}

bool CWndResizer::AddItem(HWND hParentWnd, int iID, int iFlags)
{
	return AddItem(hParentWnd, GetDlgItem(hParentWnd, iID), iFlags);
}

bool CWndResizer::AddItem(HWND hParentWnd, HWND hCtrlWnd, int iFlags)
{
	_ASSERTE(m_dwAdded < m_dwMaxControls);
	_ASSERTE(iFlags);
	_ASSERTE(hCtrlWnd);
	
	if (m_dwAdded >= m_dwMaxControls)
	{
		m_dwMaxControls++;
		m_pItems = (RITEM*)HeapReAlloc(m_hHeap, 0, m_pItems, m_dwMaxControls * sizeof(RITEM));
	}
	
	RITEM *pItems = &m_pItems[m_dwAdded];
	m_dwAdded++;
	
	RECT rect;
	
	GetWindowRect(hCtrlWnd, &rect);
	ScreenToClient(hParentWnd, (POINT*)&rect);
	ScreenToClient(hParentWnd, (POINT*)&rect.right);
	
	pItems->iFlags = iFlags;
	pItems->hWnd = hCtrlWnd;
	pItems->rcOrg = rect;
	
	if ((iFlags & RF_RELATIVE_STICK_LEFT) == RF_RELATIVE_STICK_LEFT)
	{
		_ASSERTE(m_dwOrgW > (DWORD)rect.left);
		pItems->fLeftPosRel = float(rect.left) / float(m_dwOrgW);
	}
	if ((iFlags & RF_RELATIVE_STICK_RIGHT) == RF_RELATIVE_STICK_RIGHT)
	{
		_ASSERTE(m_dwOrgW > (DWORD)rect.right);
		pItems->fRightPosRel = float(rect.right) / float(m_dwOrgW);
	}
	if ((iFlags & RF_RELATIVE_STICK_TOP) == RF_RELATIVE_STICK_TOP)
	{
		_ASSERTE(m_dwOrgH > (DWORD)rect.top);
		pItems->fTopPosRel = float(rect.top) / float(m_dwOrgH);
	}
	if ((iFlags & RF_RELATIVE_STICK_BOTTOM) == RF_RELATIVE_STICK_BOTTOM)
	{
		_ASSERTE(m_dwOrgH > (DWORD)rect.bottom);
		pItems->fBottomPosRel = float(rect.bottom) / float(m_dwOrgH);
	}
	
	return true;
}

void CWndResizer::ResizeControl(HDWP &hDwp, RITEM *pItem, DWORD w, DWORD h, int dw, int dh)
{
	RECT rect;
	
	//GetWindowRect(pItem->hWnd, &rect);
	
	//ScreenToClient(GetParent(pItem->hWnd), (POINT*)&rect);
	//ScreenToClient(GetParent(pItem->hWnd), (POINT*)&rect.right);
	rect = pItem->rcOrg;
	
	if ((pItem->iFlags & RF_RELATIVE_STICK_LEFT) == RF_RELATIVE_STICK_LEFT)
	{
		rect.left = LONG(pItem->fLeftPosRel * w);
	}
	
	if (pItem->iFlags & RF_RELATIVE_STICK_RIGHT)
	{
		if (pItem->iFlags & RF_RELATIVE_RIGHT)
			rect.right = LONG(pItem->fRightPosRel * w);
		else
			rect.right = pItem->rcOrg.right + dw;
			
		if (!(pItem->iFlags & RF_RELATIVE_STICK_LEFT))
			rect.left = pItem->rcOrg.left + dw;
	}
	
	if ((pItem->iFlags & RF_RELATIVE_STICK_TOP) == RF_RELATIVE_STICK_TOP)
	{
		rect.top = LONG(pItem->fTopPosRel * h);
	}
	
	if (pItem->iFlags & RF_RELATIVE_STICK_BOTTOM)
	{
		if (pItem->iFlags & RF_RELATIVE_BOTTOM)
			rect.bottom = LONG(pItem->fBottomPosRel * h);
		else
			rect.bottom = pItem->rcOrg.bottom + dh;
			
		if (!(pItem->iFlags & RF_RELATIVE_STICK_TOP))
			rect.top = pItem->rcOrg.top + dh;
	}
	
	hDwp = DeferWindowPos(hDwp, pItem->hWnd, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
}

void CWndResizer::Resize(DWORD w, DWORD h)
{
	_ASSERTE(m_dwAdded == m_dwMaxControls);
	
	HDWP hDwp = BeginDeferWindowPos((int)m_dwAdded);
	
	if (hDwp)
	{
		int dw = w - m_dwOrgW;
		int dh = h - m_dwOrgH;
		
		RITEM *pItem = m_pItems;
		for (DWORD i = 0; i < m_dwAdded; i++, pItem++)
		{
			ResizeControl(hDwp, pItem, w, h, dw, dh);
		}
		
		EndDeferWindowPos(hDwp);
	}
}

CWndResizer::RITEM *CWndResizer::GetItem(HWND hWndCtrl)
{
	RITEM *pItem = m_pItems;
	RITEM *pResItem = NULL;
	
	for (DWORD i = 0; i < m_dwAdded; i++, pItem++)
	{
		if (pItem->hWnd == hWndCtrl)
		{
			pResItem = pItem;
		}
	}
	
	return pResItem;
}

bool CWndResizer::ResizeItem(HWND hParentWnd, int iID, RECT *prect, DefinedOffsetFlags offset)
{
	return ResizeItem(GetDlgItem(hParentWnd, iID), prect, offset);
}

bool CWndResizer::ResizeItem(HWND hWndCtrl, RECT *prect, DefinedOffsetFlags offset)
{
	if (!prect)
		return false;
		
	bool bUpdated = false;
	
	RITEM *pItem = GetItem(hWndCtrl);
	
	if (pItem)
	{
		bool bUpdated = false;
		
		if (offset == OF_RELATIVE)
		{
			if (prect->left)
			{
				pItem->rcOrg.left += prect->left;
				bUpdated = true;
			}
			if (prect->top)
			{
				pItem->rcOrg.top += prect->top;
				bUpdated = true;
			}
			if (prect->right)
			{
				pItem->rcOrg.right += prect->right;
				bUpdated = true;
			}
			if (prect->bottom)
			{
				pItem->rcOrg.bottom += prect->bottom;
				bUpdated = true;
			}
		}
		else
		{
			if (offset == OF_ABSOLUTE)
			{
				pItem->rcOrg = *prect;
				bUpdated = true;
			}
			else
			{
				if ((offset & OF_ABSOLUTE_LEFT) && pItem->rcOrg.left != prect->left)
				{
					pItem->rcOrg.left = prect->left;
					bUpdated = true;
				}
				if ((offset & OF_ABSOLUTE_TOP) && pItem->rcOrg.top != prect->top)
				{
					pItem->rcOrg.top = prect->top;
					bUpdated = true;
				}
				if ((offset & OF_ABSOLUTE_RIGHT) && pItem->rcOrg.right != prect->right)
				{
					pItem->rcOrg.right = prect->right;
					bUpdated = true;
				}
				if ((offset & OF_ABSOLUTE_BOTTOM) && pItem->rcOrg.bottom != prect->bottom)
				{
					pItem->rcOrg.bottom = prect->bottom;
					bUpdated = true;
				}
			}
		}
	}
	
	return bUpdated;
}